// DirectoryTreeCtrl.cpp : implementation file
//
/////////////////////////////////////////////
// written by robert rostek - tecxx@rrs.at //
/////////////////////////////////////////////

//#include "stdafx.h"
#include "wintypes.h"
#include "DirectoryTreeCtrl.h"
#include "otherfunctions.h"
#include "emule.h"
#include <wx/log.h>

#ifdef _DEBUG
#undef THIS_FILE
static char THIS_FILE[]=__FILE__;
#define new DEBUG_NEW
#endif

#include "pixmaps/folder.xpm"
#include "pixmaps/hdd.xpm"

// CDirectoryTreeCtrl

#undef HTREEITEM
#define HTREEITEM wxCTreeItemId

IMPLEMENT_DYNAMIC_CLASS(CDirectoryTreeCtrl, wxCTreeCtrl)
CDirectoryTreeCtrl::CDirectoryTreeCtrl(wxWindow*& parent,int id,const wxPoint& pos,wxSize siz,int flags)
  : wxCTreeCtrl(parent,id,pos,siz,flags,wxDefaultValidator,"ShareTree"),
    m_image(16,16)
{
  //m_SharedMenu.m_hMenu = NULL;
  m_bSelectSubDirs = false;
  Init();
}

CDirectoryTreeCtrl::~CDirectoryTreeCtrl()
{
}


BEGIN_EVENT_TABLE(CDirectoryTreeCtrl, wxCTreeCtrl)
END_EVENT_TABLE()

#if 0
BEGIN_MESSAGE_MAP(CDirectoryTreeCtrl, CTreeCtrl)
	ON_NOTIFY_REFLECT(TVN_ITEMEXPANDING, OnTvnItemexpanding)
	ON_NOTIFY_REFLECT(TVN_GETDISPINFO, OnTvnGetdispinfo)
	ON_WM_LBUTTONDOWN()
	ON_NOTIFY_REFLECT(NM_RCLICK, OnNMRclickSharedList)
END_MESSAGE_MAP()
#endif



// CDirectoryTreeCtrl message handlers

void CDirectoryTreeCtrl::OnTvnItemexpanding(wxCTreeEvent& evt)
{
  //LPNMTREEVIEW pNMTreeView = reinterpret_cast<LPNMTREEVIEW>(pNMHDR);
  //int iAction = pNMTreeView->action;
  HTREEITEM hItem = evt.GetItem(); //pNMTreeView->itemNew.hItem;
  // remove all subitems
  DeleteChildren(hItem);
  
  // get the directory
  wxString strDir = GetFullPath(hItem);
  
  // fetch all subdirectories and add them to the node
  AddSubdirectories(hItem, strDir);
  
  // and sort them
  SortChildren(hItem);

  //*pResult = 0;
}

void CDirectoryTreeCtrl::OnLButtonDown(wxCTreeEvent& evt) {
//VQB adjustments to provide for sharing or unsharing of subdirectories when control key is Down 
  static int __counter=0;
  UINT uFlags; 
  HTREEITEM hItem = evt.GetItem(); //HitTest(point, &uFlags); 
  HTREEITEM tItem = GetFirstVisibleItem(); // VQB mark initial window position 
  int flags=0;
  wxCTreeItemId myitem=HitTest(evt.GetPoint(),flags);
  // this event is launced _after_ checkbox value is set.. if it is set at all
  if ( (hItem.IsOk()) && flags&wxCTREE_HITTEST_CHECKBOX ) { // && (uFlags & TVHT_ONITEMSTATEICON)) { 
    CheckChanged(hItem, IsChecked(hItem)); 
    if (evt.IsControlDown()) {// & MK_CONTROL) { // Is control key down? 
      bool exp;
      exp=false;
      Toggle(hItem);
      HTREEITEM hChild; 
      long cookie=993+(++__counter);
      hChild = GetFirstChild(hItem,cookie);//GetChildItem(hItem); 
      while (hChild.IsOk())// != NULL) 
      { 
        MarkChilds(hChild,IsChecked(hItem)); 
        //hChild = GetNextChild(hChild,cookie); //GetNextSiblingItem( hChild ); 
	hChild=GetNextSibling(hChild);
      } 
      Toggle(hItem);

      // font won't get set otherwise...
      Toggle(GetItemParent(hItem));
      Toggle(GetItemParent(hItem));
    } 
  } 
  //SelectSetFirstVisible(tItem); // VQB - restore window scroll to initial position 
  //CTreeCtrl::OnLButtonDown(nFlags, point); 
} 

void CDirectoryTreeCtrl::MarkChilds(HTREEITEM hChild,bool mark) { 
  static long int __counter=1;

  CheckChanged(hChild, mark); 
  SetChecked(hChild,mark);  
  bool exp;
  exp=false;
  Toggle(hChild);

  HTREEITEM hChild2; 
  long int cookie=++__counter;
  hChild2 = GetFirstChild(hChild,cookie);//GetChildItem(hChild); 
  while( hChild2.IsOk() ) 
  {     
    MarkChilds(hChild2,mark); 
    //hChild2 = GetNextChild(hChild,cookie); //GetNextSiblingItem( hChild2 ); 
    hChild2 = GetNextSibling(hChild2);
  } 
  Toggle(hChild);
  //if(exp) {Collapse(hChild);}//, TVE_TOGGLE); // VQB - restore tree to initial disposition 
}

#if 0
void CDirectoryTreeCtrl::OnTvnGetdispinfo(NMHDR *pNMHDR, LRESULT *pResult)
{
	LPNMTVDISPINFO pTVDispInfo = reinterpret_cast<LPNMTVDISPINFO>(pNMHDR);
	pTVDispInfo->item.cChildren = 1;
	*pResult = 0;
}
#endif

void CDirectoryTreeCtrl::Init(void)
{
#if 0
	ShowWindow(SW_HIDE);
	DeleteAllItems();

	ModifyStyle( 0, TVS_CHECKBOXES );

	// START: added by FoRcHa /////////////
	WORD wWinVer = theApp.glob_prefs->GetWindowsVersion();	// maybe causes problems on 98 & nt4
	if(wWinVer == _WINVER_2K_ || wWinVer == _WINVER_XP_ || wWinVer == _WINVER_ME_)		
	{
	SHFILEINFO shFinfo;
	HIMAGELIST hImgList = NULL;

	hImgList = (HIMAGELIST)SHGetFileInfo("C:\\", 0, &shFinfo, sizeof(shFinfo),
											SHGFI_SYSICONINDEX | SHGFI_SMALLICON);
	if(!hImgList)
	{
		TRACE(_T("Cannot retrieve the Handle of SystemImageList!"));
		return;
	}

	m_image.m_hImageList = hImgList;
	SetImageList(&m_image, TVSIL_NORMAL);
	}
	////////////////////////////////


	char drivebuffer[500];
	::GetLogicalDriveStrings(500, drivebuffer);
	while(drivebuffer[0] != '\0')
	{
		char drive[4];
		memccpy(drive, drivebuffer, '\0', 10);
		if (tolower(drive[0]) != tolower('A') && tolower(drive[0]) != tolower('B')) { // <-- added 
			drive[2] = '\0'; 
			AddChildItem(NULL, drive); 
		}
		memmove(drivebuffer, drivebuffer+4, 500);
	}
	ShowWindow(SW_SHOW);
#endif
	// init image(s)
	m_image.Add(wxBitmap(folder_xpm));
	m_image.Add(wxBitmap(hdd_xpm));
	SetImageList(&m_image);

	DeleteAllItems();
	// no drives. just root!
	HTREEITEM root=AddRoot("/");
	SetItemImage(root,1);
	HTREEITEM test=AppendItem(root,"Cool. Works");
	//SetChecked(test,TRUE);
}

HTREEITEM CDirectoryTreeCtrl::AddChildItem(HTREEITEM hRoot, wxString strText)
{
  wxString strPath = GetFullPath(hRoot);
  if (hRoot.IsOk() && strPath.Right(1) != "/")
    strPath += "/";
  wxString strDir = strPath + strText;

  HTREEITEM item=AppendItem(hRoot,strText);
  SetItemImage(item,0); // it is folder!
  if(HasSharedSubdirectory(strDir)) 
    SetItemBold(item,TRUE);
  if(IsShared(strDir)) 
    SetChecked(item,TRUE);
  if(HasSubdirectories(strDir)) 
    AppendItem(item,"."); // trick. will show + 
#if 0
	TV_INSERTSTRUCT itInsert;
	memset(&itInsert, 0, sizeof(itInsert));
	
	// START: changed by FoRcHa /////
	WORD wWinVer = theApp.glob_prefs->GetWindowsVersion();
	if(wWinVer == _WINVER_2K_ || wWinVer == _WINVER_XP_ || wWinVer == _WINVER_ME_)		
	{
		itInsert.item.mask = TVIF_CHILDREN | TVIF_HANDLE | TVIF_TEXT |
							TVIF_STATE | TVIF_IMAGE | TVIF_SELECTEDIMAGE;
		itInsert.item.stateMask = TVIS_BOLD | TVIS_STATEIMAGEMASK;
	}
	else
	{
		itInsert.item.mask = TVIF_CHILDREN | TVIF_HANDLE | TVIF_TEXT | TVIF_STATE;
		itInsert.item.stateMask = TVIS_BOLD;
	}
	// END: changed by FoRcHa ///////
	
	if (HasSharedSubdirectory(strDir))
		itInsert.item.state = TVIS_BOLD;
	else
		itInsert.item.state = 0;
	if (HasSubdirectories(strDir))
		itInsert.item.cChildren = I_CHILDRENCALLBACK;		// used to display the + symbol next to each item
	else
		itInsert.item.cChildren = 0;

	itInsert.item.pszText = strText.GetBuffer();
	itInsert.item.cchTextMax = strText.GetLength();
	itInsert.hInsertAfter = TVI_SORT;
	itInsert.hParent = hRoot;
	
	// START: added by FoRcHa ////////////////
	if(wWinVer == _WINVER_2K_ || wWinVer == _WINVER_XP_ || wWinVer == _WINVER_ME_)		
	{
	CString strTemp = strDir;
	if(strTemp.Right(1) != "\\")
		strTemp += "\\";
	
	UINT nType = GetDriveType(strTemp);
	if(DRIVE_REMOVABLE <= nType && nType <= DRIVE_RAMDISK)
		itInsert.item.iImage = nType;

	SHFILEINFO shFinfo;
	if(!SHGetFileInfo(strTemp, 0, &shFinfo,	sizeof(shFinfo),
					SHGFI_ICON | SHGFI_SMALLICON))
	{
		TRACE(_T("Error Gettting SystemFileInfo!"));
		itInsert.itemex.iImage = 0; // :(
	}
	else
	{
		itInsert.itemex.iImage = shFinfo.iIcon;
		DestroyIcon(shFinfo.hIcon);
	}
	
	if(!SHGetFileInfo(strTemp, 0, &shFinfo, sizeof(shFinfo),
						SHGFI_ICON | SHGFI_OPENICON | SHGFI_SMALLICON))
	{
		TRACE(_T("Error Gettting SystemFileInfo!"));
		itInsert.itemex.iImage = 0;
	}
	else
	{
		itInsert.itemex.iSelectedImage = shFinfo.iIcon;
		DestroyIcon(shFinfo.hIcon);
	}
	}
	// END: added by FoRcHa //////////////
	
	HTREEITEM hItem = InsertItem(&itInsert);
	if (IsShared(strDir))
		SetCheck(hItem);
	strText.ReleaseBuffer();

	return hItem;
#endif
}

wxString CDirectoryTreeCtrl::GetFullPath(HTREEITEM hItem)
{
	wxString strDir;
	HTREEITEM hSearchItem = hItem;
	// don't traverse to the root item.. it will cause extra / to the path
	while(hSearchItem.IsOk())// && hSearchItem!=GetRootItem())
	{
		strDir = GetItemText(hSearchItem) + "/" + strDir;
		hSearchItem = GetItemParent(hSearchItem);
	}
	return strDir;
}

void CDirectoryTreeCtrl::AddSubdirectories(HTREEITEM hRoot, wxString strDir)
{
	if (strDir.Right(1) != "/")
		strDir += "/";
	wxString fname;
	wxString dirname=strDir+"*";
	// we must collect values first because we'll call FindFirstFile() again in 
	// AddChildItem()..
	wxArrayString ary;

	fname=wxFindFirstFile(dirname,wxDIR);
	while(!fname.IsEmpty()) {
	  if(!wxDirExists(fname)) {
	    fname=wxFindNextFile();
	    continue;
	  }
	  if(fname.Find('/',TRUE)!=-1)
	    fname=fname.Mid(fname.Find('/',TRUE)+1);

	  ary.Add(fname);
	  fname=wxFindNextFile();
	}
	// then add them
	for(int i=0;i<ary.GetCount();i++) {
	  AddChildItem(hRoot,ary[i]);
	}
#if 0
	if (!::SetCurrentDirectory(strDir))
		return;
	CFileFind finder;
	BOOL bWorking = finder.FindFile("*.*");
	while (bWorking)
	{
		bWorking = finder.FindNextFile();
		if (finder.IsDots())
			continue;
		if (finder.IsSystem())
			continue;
		if (!finder.IsDirectory())
			continue;
		
		wxString strFilename = finder.GetFileName();
		if (strFilename.ReverseFind('\\') != -1)
			strFilename = strFilename.Mid(strFilename.ReverseFind('\\') + 1);
		AddChildItem(hRoot, strFilename);
	}
	finder.Close();
#endif
}

bool CDirectoryTreeCtrl::HasSubdirectories(wxString strDir)
{
  wxLogNull logNo; // prevent stupid log windows if we try to traverse somewhere we
  // have no access.
	if (strDir.Right(1) != "/")
		strDir += "/";
	wxString fname=wxFindFirstFile(strDir+"*",wxDIR);
	if(!fname.IsEmpty())
	  return TRUE; // at least one directory...
	return FALSE; // no match
#if 0
	::SetCurrentDirectory(strDir);
	CFileFind finder;
	BOOL bWorking = finder.FindFile("*.*");
	while (bWorking)
	{
		bWorking = finder.FindNextFile();
		if (finder.IsDots())
			continue;
		if (finder.IsSystem())
			continue;
		if (!finder.IsDirectory())
			continue;
		finder.Close();
		return true;
	}
	finder.Close();
	return false;
#endif
}


void CDirectoryTreeCtrl::GetSharedDirectories(wxArrayString* list)
{
  //for (POSITION pos = m_lstShared.GetHeadPosition(); pos != NULL; )
  for(int i=0;i<m_lstShared.GetCount();i++)
    list->Add(m_lstShared[i]);
}
void CDirectoryTreeCtrl::SetSharedDirectories(wxArrayString* list)
{
  m_lstShared.Clear();

  for (int i=0;i<list->GetCount();i++)
    {
      wxString str = list->Item(i);//list->GetNext(pos);
      if (str.Right(1) != '/')
	str += '/';
      m_lstShared.Add(str);
    }
  Init();
}

bool CDirectoryTreeCtrl::HasSharedSubdirectory(wxString strDir)
{
  if (strDir.Right(1) != '/')
    strDir += "/";
  strDir.MakeLower();
  for (int i=0;i<m_lstShared.GetCount();i++) 
    {
      wxString str = m_lstShared[i];//.GetNext(pos);
      str.MakeLower();
      if (str.Find(strDir) == 0 && strDir != str)//strDir.GetLength() != str.GetLength())
	return true;
    }
  return false;
}

void CDirectoryTreeCtrl::CheckChanged(HTREEITEM hItem, bool bChecked)
{
	wxString strDir = GetFullPath(hItem);
	if (bChecked)
		AddShare(strDir);
	else
		DelShare(strDir);

#if 0
	UpdateParentItems(hItem);
	GetItemParent()->SendMessage(WM_COMMAND, USRMSG_ITEMSTATECHANGED, (long)m_hWnd);
#endif
}

bool CDirectoryTreeCtrl::IsShared(wxString strDir)
{
	if (strDir.Right(1) != '/')
		strDir += '/';
	for (int i=0;i<m_lstShared.GetCount();i++)
	{
		wxString str = m_lstShared[i];
		if (str.Right(1) != '/')
			str += '\\';
		if (str.CmpNoCase(strDir) == 0)
			return true;
	}
	return false;
}

void CDirectoryTreeCtrl::AddShare(wxString strDir)
{
	if (strDir.Right(1) != '/')
		strDir += '/';
	
	if (IsShared(strDir))
		return;
	m_lstShared.Add(strDir);
}

void CDirectoryTreeCtrl::DelShare(wxString strDir)
{
	if (strDir.Right(1) != '/')
		strDir += '/';
	m_lstShared.Remove(strDir.GetData());
}

void CDirectoryTreeCtrl::UpdateParentItems(HTREEITEM hChild)
{
#if 0
	HTREEITEM hSearch = GetItemParentItem(hChild);
	while(hSearch != NULL)
	{
		if (HasSharedSubdirectory(GetFullPath(hSearch)))
			SetItemState(hSearch, TVIS_BOLD, TVIS_BOLD);
		else
			SetItemState(hSearch, 0, TVIS_BOLD);
		hSearch = GetItemParentItem(hSearch);
	}
#endif
}


#if 0
void CDirectoryTreeCtrl::OnNMRclickSharedList(NMHDR *pNMHDR, LRESULT *pResult)
{
	// get item under cursor
	POINT point;
	::GetCursorPos(&point);
	CPoint p = point;
	ScreenToClient(&p);
	HTREEITEM hItem = HitTest(p);

	// create the menu
	m_SharedMenu.DestroyMenu();
	m_SharedMenu.CreatePopupMenu();
	if (m_lstShared.GetCount() == 0)
		m_SharedMenu.AddMenuTitle(GetResString(IDS_NOSHAREDFOLDERS));
	else
		m_SharedMenu.AddMenuTitle(GetResString(IDS_SHAREDFOLDERS));

	// add right clicked folder, if any
	if (hItem)
	{
		m_strLastRightClicked = GetFullPath(hItem);
		if (!IsShared(m_strLastRightClicked))
			m_SharedMenu.AppendMenu(MF_STRING, MP_SHAREDFOLDERS_FIRST-1, (LPCTSTR)(GetResString(IDS_VIEW1) + m_strLastRightClicked +GetResString(IDS_VIEW2)));
	}

	// add all shared directories
	int iCnt = 0;
	for (POSITION pos = m_lstShared.GetHeadPosition(); pos != NULL; iCnt++)
		m_SharedMenu.AppendMenu(MF_STRING,MP_SHAREDFOLDERS_FIRST+iCnt, (LPCTSTR)m_lstShared.GetNext(pos));

	// display menu
	m_SharedMenu.TrackPopupMenu(TPM_LEFTALIGN |TPM_RIGHTBUTTON, point.x, point.y, this);
	*pResult = 0;
}
#endif

#if 0
BOOL CDirectoryTreeCtrl::OnCommand(WPARAM wParam,LPARAM lParam ){
	if (wParam < MP_SHAREDFOLDERS_FIRST)
	{
		ShellExecute(NULL, "open", m_strLastRightClicked, NULL, NULL, SW_SHOW);
		return false;
	}
	int cnt = 0;
	for (POSITION pos = m_lstShared.GetHeadPosition(); pos != NULL; )
	{
		wxString str = m_lstShared.GetNext(pos);
		if (cnt == wParam-MP_SHAREDFOLDERS_FIRST)
		{
			ShellExecute(NULL, "open", str, NULL, NULL, SW_SHOW);
			return true;
		}
		cnt++;
	}
	return true;
}
#endif

bool CDirectoryTreeCtrl::ProcessEvent(wxEvent& evt)
{
  if(evt.GetEventType()==wxEVT_COMMAND_CTREE_ITEM_EXPANDING) {
    OnTvnItemexpanding((wxCTreeEvent&)evt);
    return true;
  }
  if(evt.GetEventType()==wxEVT_COMMAND_CTREE_ITEM_LEFT_CLICK) {
    OnLButtonDown((wxCTreeEvent&)evt);
    return true;
  }
  return wxCTreeCtrl::ProcessEvent(evt);
}
